package com.xb.system.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.google.common.hash.BloomFilter;
import com.xb.system.redis.UserPhoneBloomFilterConfig;
import com.xb.system.service.FileHandler;
import com.xb.model.domain.Users;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


@Component
@Slf4j
public class ExcelDocumentHandler implements FileHandler {

    @Value("${file.batch.size}")
    private int batchSize;
    @Value("${file.thread.pool.size}")
    private int threadPoolSize;
    @Autowired
    private DynamicDataSplitterServiceImpl splitterService;
    @Autowired
    private UserPhoneBloomFilterConfig userPhoneBloomFilterConfig;

    @Override
    public void handleFile(String file) throws IOException {
        BloomFilter<String> bloomFilter = userPhoneBloomFilterConfig.createBloomFilter();
        try (InputStream is = Files.newInputStream(Paths.get(file))) {
            ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);

            EasyExcel.read(is, String.class, new ExcelDataListener(bloomFilter))
                    .sheet()
                    .doRead();

            executor.shutdown();
            try {
                executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
            } catch (InterruptedException e) {
                log.error("线程池在等待任务完成时被中断：{}", e.getMessage());
                Thread.currentThread().interrupt();
            }

        } catch (IOException e) {
            log.error("Error processing Excel document: {}", e.getMessage());
            throw e;
        }
    }

    private class ExcelDataListener extends AnalysisEventListener<String> {
        BloomFilter<String> bloomFilter;
        
        ExcelDataListener(BloomFilter<String> bloomFilter) {
            this.bloomFilter = bloomFilter;
        }
        private List<Users> batch = new ArrayList<>();

        @Override
        public void invoke(String line, AnalysisContext analysisContext) {
            batch.addAll(splitterService.processLine(line.trim(), bloomFilter));
            if (batch.size() >= batchSize) {
                splitterService.saveBatch(batch);
                log.info("已保存 {} 条数据到数据库。", batch.size());
                batch.clear();
            }
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
            splitterService.saveBatch(batch);
            log.info("数据读取完毕");
            batch.clear();
        }
    }

    /*@Override
    public void handleFile(MultipartFile file) throws IOException {
        try (InputStream is = file.getInputStream();
             XSSFWorkbook workbook = new XSSFWorkbook(is)) {
            ExcelReaderBuilder readerBuilder = EasyExcel.read();
            readerBuilder.file(file.getInputStream());
            // TODO 采用EasyExcel来操作Excel文件性能更高，能避免OOM
            XSSFSheet sheet = workbook.getSheetAt(0); // 假设处理第一个Sheet页

            ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);

            int rowCount = sheet.getPhysicalNumberOfRows();
            int chunkSize = (int) Math.ceil((double) rowCount / threadPoolSize);

            for (int i = 0; i < threadPoolSize; i++) {
                int fromIndex = i * chunkSize;
                int toIndex = Math.min(fromIndex + chunkSize, rowCount);

                List<Row> rows = new ArrayList<>();
                for (int rowIndex = fromIndex; rowIndex < toIndex; rowIndex++) {
                    Row row = sheet.getRow(rowIndex);
                    if (row != null) {
                        rows.add(row);
                    }
                }

                executor.submit(() -> processRows(rows));
            }

            executor.shutdown();
            try {
                executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
            } catch (InterruptedException e) {
                log.error("线程池在等待任务完成时被中断：{}", e.getMessage());
                Thread.currentThread().interrupt();
            }

        } catch (IOException e) {
            log.error("Error processing Excel document: {}", e.getMessage());
            throw e;
        }
    }

    private void processRows(List<Row> rows) {
        List<Users> batch = new ArrayList<>();
        for (Row row : rows) {
            Cell cell0 = row.getCell(0);
            Cell cell1 = row.getCell(1);
            if (cell0 == null || cell1 == null) {
                continue;
            }

            String phone = cell0.toString().trim();
            String name = cell1.toString().trim();

            if (!phone.matches("^1[3456789]\\d{9}$")) {
                continue;
            }

            String maskedName = StrUtil.hide(name, 1, name.length());
            batch.add(new Users(null, phone, maskedName));

            // 处理可能存在的额外手机号，假设这些额外的手机号在同一行的其他列中
            for (int j = 2; j < row.getPhysicalNumberOfCells(); j++) {
                Cell extraCell = row.getCell(j);
                if (extraCell != null) {
                    String extraPhone = extraCell.toString().trim();
                    if (extraPhone.matches("^1[3456789]\\d{9}$")) {
                        batch.add(new Users(null, extraPhone, maskedName));
                    }
                }
            }

            if (batch.size() >= batchSize) {
                saveBatch(batch);
                batch.clear();
            }
        }

        if (!batch.isEmpty()) {
            saveBatch(batch);
        }
    }

    private void saveBatch(List<Users> batch) {
        // 实现保存批处理逻辑，使用了动态数据分片器中的方法
        MyDynamicDataSplitterServiceImpl splitterService = new MyDynamicDataSplitterServiceImpl();
        splitterService.saveBatch(batch);
        log.info("已保存 {} 条数据到数据库。", batch.size());
    }*/

}
